package com.zhiteng.controller;

import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.zhiteng.entity.CourseTime;
import com.zhiteng.entity.LeaveBill;
import com.zhiteng.entity.Procdef;
import com.zhiteng.entity.Teacher;
import com.zhiteng.service.CourseTableService;
import com.zhiteng.service.CourseTimeService;
import com.zhiteng.service.LeaveService;
import com.zhiteng.service.ProcessService;
import com.zhiteng.service.SmartCampusApiService;
import com.zhiteng.service.TeacherService;
import com.zhiteng.utils.common.DateTool;
import com.zhiteng.utils.common.DateUtil;
import com.zhiteng.utils.common.ZTResult;
import com.zhiteng.vo.ProcdefModel;


/**  
* <p>Title: LeaveProcessController.java</p>  
* <p>Description: 请假流程相关Controller</p>  
* @author dragon  
* @date 2018年12月2日  
* @version 1.0  
*/
@Controller
@RequestMapping("/leave")
public class LeaveProcessController {
	@Autowired
	private ProcessService processService;
	@Autowired
	private CourseTableService courseTableService;
	@Autowired
	private LeaveService leaveService;
	@Autowired
	private CourseTimeService courseTimeService;
	@Autowired
	private TeacherService teacherService;
	@Autowired
	private SmartCampusApiService smartCampusApiService;
	
	
	/**
	 * 
	* @Title: saveProcdef  
	* @Description: 创建流程定义 
	* @param procdefs
	* @return ZTResult<Void>   
	* @throws
	 */
	@RequestMapping("/saveLeaveProcdef")
	@ResponseBody
	public ZTResult<Void> saveProcdef(ProcdefModel procdefs){
		List<Procdef> pdList = procdefs.getProcdefs();
		if(pdList==null || pdList.isEmpty()) return ZTResult.result(1, "保存失败，请先设置流程定义");
		//	参数校验
		for (int i=0;i<pdList.size();i++) {
			if(StringUtils.isAnyBlank(pdList.get(i).getAssignee_id(),pdList.get(i).getSchool_id())) {
				return ZTResult.result(1,"保存失败，请检查是否有参数为空");
			}
			if("null".equals(pdList.get(i).getSequence()+"") || "null".equals(pdList.get(i).getType()+"")) {
				return ZTResult.result(1,"保存失败，请检查是否有参数为空");
			}
			if("undefined".equals(pdList.get(i).getAssignee_id())) {
				return ZTResult.result(1,"保存失败，审批人id为undefined");
			}
			if(pdList.get(i).getType()==1 && StringUtils.isBlank(pdList.get(i).getHours()+"")) {
				return ZTResult.result(1,"保存失败，请假单的流程定义必须设置时间");
			}
			if(i==0 && pdList.get(i).getType()==1 && pdList.get(i).getHours()!=0) {
				return ZTResult.result(1,"保存失败，请假单的第一个审批人的时间必须为0");
			}
			if(i<pdList.size()-1 && pdList.get(i).getType()==1 && pdList.get(i).getHours()>=pdList.get(i+1).getHours()) {
				return ZTResult.result(1,"保存失败，清单流程中后面的审批人的时间必须大于前面的审批人的时间");
			}
		}
		
		//1.删除之前的流程定义
		processService.delProcdef(pdList.get(0).getSchool_id(),pdList.get(0).getType());
		//2.保存新的流程定义
		int count = processService.saveProcdefBatch(pdList);
		if(count==pdList.size()) {
			return ZTResult.result(0, "保存成功");
		}
		return ZTResult.result(1, "保存失败");
	}
	
	
	/**
	 * 
	* @Title: queryTotalCourse  
	* @Description: 计算请假期间该教师的总课时
	* @param teacher_id 请假的教师id
	* @param school_id 所属学校id
	* @param startStr 请假开始时间
	* @param endStr 请假结束时间				//	学年 学期？？？？？？？？？？？（一个学校数据库中只有一个学期的课程表）
	* @return ZTResult<Integer>   
	* @throws
	 */
	@RequestMapping("/queryTotalCourse")
	@ResponseBody
	public ZTResult<Integer> queryTotalCourse(LeaveBill bill){
		
		if(StringUtils.isAnyBlank(bill.getTeacher_id(),bill.getSchool_id(),bill.getStartStr(),bill.getEndStr())) {
			return ZTResult.result(1,"查询失败，请检查是否有参数为空");
		}
		String startStr = bill.getStartStr().trim();	//2018-12-04 09:30
		String endStr = bill.getEndStr().trim();	//2018-12-24 16:00
		if(startStr.length()!=16 || endStr.length()!=16) {
			return ZTResult.result(1,"查询失败，日期时间格式不正确");
		}
		try {
			if(DateUtil.String2Date(endStr).getTime() - DateUtil.String2Date(startStr).getTime()< 0) {
				return ZTResult.result(1, "结束时间必须大于开始时间");
			}
		} catch (ParseException e) {
			return ZTResult.result(1, "请检查日期格式");
		}
		
		//	将请假开始时间和结束时间改成double类型，便于比较大小
		double startTime = Double.parseDouble(startStr.split("\\s")[1].replace(":", "."));	//	09.30
		double endTime = Double.parseDouble(endStr.split("\\s")[1].replace(":", "."));	//	16.00
		
	//	一、计算请假期间的总课时
		//	1.1、查询指定教师一周中的每一天各有几节课
		Map<Integer,Integer> map1 = 
				courseTableService.queryCountNodeEveryDay(bill.getSchool_id(), bill.getTeacher_id());
		if(map1.get(0)==-1) {
			return ZTResult.result(1,"查询失败，该教师没有课或该教师不存在");
		}
		
		//	1.2、计算请假期间（包括第一天和最后一天），星期一、星期二、。。。星期日各有多少天 
		Map<Integer,Integer> map2 = DateTool.countEveryWeek(startStr.split("\\s")[0], endStr.split("\\s")[0]);
		//	1.3、请假期间总课时（包括第一天和最后一天）
		int total_course = map1.get(1)*map2.get(1) + map1.get(2)*map2.get(2) + map1.get(3)*map2.get(3) + map1.get(4)*map2.get(4) + map1.get(5)*map2.get(5) + map1.get(6)*map2.get(6) + map1.get(7)*map2.get(7);
		
		/////////////////////////////////////--	计算请假期间有几节属于他的课没有上	--////////////////////////////////////////
		//	1.4、下面还要减去第一天和最后一天实际上的课时
		//		1.4.1、获取该学校上课时间表，并按上课节次升序排序
		List<CourseTime> courseTimeList = courseTimeService.queryCourseTimeBySchoolId(bill.getSchool_id());
		if(courseTimeList==null || courseTimeList.isEmpty()) {
			return ZTResult.result(1,"查询失败，请先联系管理员上传上课时间表");
		}
		
		//		1.4.2、计算请假第一天实际上的课时：开始和结束时间在同一天和不在同一天两种情况
		if(startStr.split("\\s")[0].equals(endStr.split("\\s")[0])) { //	请假开始时间和结束时间在同一天
			String week = DateTool.dateToWeekStr(startStr.split("\\s")[0]);
			int weekInt = DateTool.dateToWeek(startStr.split("\\s")[0]);
			//	该教师请假当前有几节属于自己的课
			int  count = map1.get(weekInt);
			int num = 0;	//	请假当天有num节课上不了
			if(startTime>=courseTimeList.get(courseTimeList.size()-1).getStart()){	//	请假当天的课全部上不了
				return ZTResult.result(0,"查询成功",count);
			}else if(endTime<=courseTimeList.get(0).getStart()) { 	//	请假当天的课全部能上
				return ZTResult.result(0,"查询成功",0);
			}else {	
				int startNode = 0;
				int endNode = 0;
				for(int i=0;i<courseTimeList.size();i++) {
					if(startTime>=courseTimeList.get(i).getStart() && startTime<courseTimeList.get(i+1).getStart()) {	//	第i+1节课及之前的课上不了
						startNode = i+1;
					}
					if(endTime>=courseTimeList.get(i).getEnd() && startTime<courseTimeList.get(i+1).getEnd()) {	//	第i+1节及之后的课上不了
						endNode = i+1;
						break;
					}
					//	算出第startNode节课之后（不含）且在endNode节课之前（不含）的属于该教师的课程数
					num = courseTableService.queryCountBetween(bill.getTeacher_id(),week,startNode,endNode);
				}
				return ZTResult.result(0,"查询成功",num);
			}
			
		}else {	//	请假开始时间和结束时间不在同一天
			String week1 = DateTool.dateToWeekStr(startStr.split("\\s")[0]);
			int weekInt1 = DateTool.dateToWeek(startStr.split("\\s")[0]);
			int firstCount = 0;	//	请假第一天实际上几节课
			if(startTime<courseTimeList.get(0).getStart()) {	//	第一天的课一节都上不了
				firstCount = 0;
			}else if(startTime>courseTimeList.get(courseTimeList.size()-1).getEnd()){	//	第一天的课全部可以上
				firstCount = map1.get(weekInt1);
			}else {	
				for(int i=0;i<courseTimeList.size();i++) {
					if(startTime>=courseTimeList.get(i).getEnd() && startTime<courseTimeList.get(i+1).getEnd()) {	//	前i+1节课可以上课
						//	查询有该教师第一天实际上了几节课
						firstCount = courseTableService.queryFirstCount(bill.getTeacher_id(),week1,i+1);
						break;
					}
				}
			}
			//		1.4.3、计算请假最后一天实际上的课时
			String week2 = DateTool.dateToWeekStr(endStr.split("\\s")[0]);
			int weekInt2 = DateTool.dateToWeek(endStr.split("\\s")[0]);
			int endCount = 0;	//	请假第一天实际上几节课
			if(endTime<courseTimeList.get(0).getStart()) {	//	最后一天课全部可以上
				endCount = map1.get(weekInt2);
			}else if(endTime>courseTimeList.get(courseTimeList.size()-1).getEnd()){	//	最后一天课一节都上不了
				endCount = 0;
			}else {	
				for(int i=0;i<courseTimeList.size();i++) {
					if(endTime>courseTimeList.get(i).getStart() && endTime<=courseTimeList.get(i+1).getStart()) {	//	前i+1节课上不了
						//	查询有该教师最后一天实际上了几节课
						endCount = map1.get(weekInt2) - courseTableService.queryFirstCount(bill.getTeacher_id(),week2,i);
						break;
					}
				}
			}
			return ZTResult.result(0,"查询成功",total_course-firstCount-endCount);
		}
		
		/////////////////////////////////////////////////////////////////////////////
		
		
	}
	
	
	/**
	 * 
	* @Title: createLeaveBill  
	* @Description: 创建请假单，启动请假流程（同一事务中完成）
	* @param teacher_id 请假的教师id
	* @param school_id 所属学校id
	* @param reason 请假原因：事假、病假、产假等
	* @param startStr 请假开始时间
	* @param endStr 请假结束时间
	* @param total_course 请假总课时
	* @return ZTResult<Void>   
	* @throws
	 */
	@RequestMapping("/createLeaveBill")
	@ResponseBody
	public ZTResult<Void> createLeaveBill(LeaveBill bill){
		
		if(StringUtils.isAnyBlank(bill.getTeacher_id(),bill.getSchool_id(),bill.getStartStr(),
				bill.getEndStr(),bill.getReason())  || "null".equals(bill.getTotal_course()+"")) {
			return ZTResult.result(1,"提交失败，请检查是否有参数为空");
		}
		
		Teacher teacher = teacherService.queryTeacherById(bill.getTeacher_id());
		if(teacher==null) {
			return ZTResult.result(1, "该教师不存在");
		}
		bill.setTeacherName(teacher.getName());
		bill.setStatus(0);	//	开始审批(审批中)
		bill.setType(1);
		bill.setRevocable(0); //	可撤销
		bill.setCreateDate(new Date());
		String startStr = bill.getStartStr().trim();	//2018-12-04 09:00
		String endStr = bill.getEndStr().trim();	//2018-12-24 16:00
		try {
			bill.setStart(DateUtil.String2Date(startStr));
			bill.setEnd(DateUtil.String2Date(endStr));
		} catch (ParseException e) {
			return ZTResult.result(1, "请检查日期格式");
		}
		
	//	二、根据请假的时间确定需要走哪些流程
		//	2.1、计算请假的小时数，如 7.5
		double hours = DateUtil.getHours(bill.getStart(), bill.getEnd());
		if(hours < 0) {
			return ZTResult.result(1, "结束时间必须大于开始时间");
		}
		bill.setTotal_hour(hours);
		//	2.2、查询该学校请假单的流程定义(排好序的：orderBy("sequence").asc())
		List<Procdef> procdefList = processService.queryProcdef(bill.getSchool_id(),1);	//	type=1表示请假流程
		//	2.3、创建并保存请假单以及需要走的流程
		if(procdefList!=null && !procdefList.isEmpty()) {
			//	数据库中保存请假单信息，并创建请假流程保存到数据库，并给第一个审批人发送消息
			leaveService.saveLeaveBill(bill,procdefList);
			
			//	推送消息(先获取第一个审批人)
			Teacher t = teacherService.queryTeacherById(procdefList.get(0).getAssignee_id());
			Map<String,String> data = new HashMap<>();
			data.put("wxuserid", t.getWxuserid());
			data.put("content", bill.getTeacherName()+"的请假单待你审批，<a href='http://www.zhitengit.com:8200/courseArrangementSystem/commonProcess/queryMyUncomplatedBills?schoolId="+bill.getSchool_id()+"&teacherId="+t.getUserid()+"'>去审批</a>");
			Map<String, Object> sendMsg = smartCampusApiService.sendMsg(bill.getSchool_id(), data);
			System.out.println(sendMsg);
			
			return ZTResult.result(0, "提交成功");
		}else{
			return ZTResult.result(1, "提交失败，请假流程未定义");
		}
		
	}
	
}
